<?php
/**
 * 框架 - HTTP请求信息处理类
 * 
 * @version $Id: Request.php 425 2013-02-20 02:20:43Z linsir123 $
 * @package Core
 */
class Request
{
	/**
	 * @var 请求的路径信息(采用相对路径)
	 */
	public $domain;
	
	/**
	 * @var 请求路由信息
	 */
	public $route;
	
	/**
	 * @var 路由的获取方式
	 * // 配置
	 */
	public $urlModel;
	
	/**
	 * @var 应用路由配置信息
	 * // 配置
	 */
	public $urlRoutes;
	
	/**
	 * @var 控制器相关信息
	 */
	public $ctrlData = array();
	
	/**
	 * 构造函数
	 */
	public function __construct()
	{
		$uri = substr($_SERVER['REQUEST_URI'], 0, strrpos($_SERVER['REQUEST_URI'], '/'));
		$phpSelf = substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
		if (empty($phpSelf) || strpos($uri, $phpSelf) === false) 
			$phpSelf = '';
			
		///
		$this->domain = htmlspecialchars(preg_replace("/\/+(api|archiver|wap)?\/*$/i", '', $phpSelf) . '/');
		$this->urlRoutes = App::O('main.urlRoutes');
		$this->urlModel = App::O('main.urlMode');
	}
	
	/**
	 * 初始化
	 * 
	 * @param string $route 路由信息
	 */
	public function parse($route = '')
	{
		$this->_initRoute($route);
		$this->_initQuery();
		
		///
		return $this->ctrlData;
	}
	
	/**
	 * 构造一个请求地址
	 * 
	 * @param string $route 路由信息
	 * @param array $params 其它参数
	 * @param bool $full 是否包含完整的域名信息
	 * @return string
	 */
	public function create($route = '', $params = array(), $full = false)
	{
		$url = $route;
		if ($this->urlModel != URL_REWRITE) 
			$url = basename($_SERVER['SCRIPT_NAME']) .'/'. $url;
			
		if (is_array($params)) {
			foreach ($params as $key => $val) 
				$url .= '/'. rawurlencode($key) .'/' .rawurlencode($val);
		}
		
		///
		$domain = $this->domain;
		if ($full) {
			$prefix = 'http://'. $_SERVER['SERVER_NAME'];
			if ($_SERVER['SERVER_PORT'] != 80) 
				$prefix .= ':'. $_SERVER['SERVER_PORT'];
				
			$domain = $prefix . $domain;
		}
		
		///
		return $domain . $url;
	}
	
	
	/// 以下为私有方法 ///
	
	
	/**
	 * 分析请求路径信息
	 */
	private function _initRoute($route = '')
	{
		if (empty($route)) {
			if ($this->urlModel == URL_PHPINFO && isset($_SERVER['PATH_INFO'])) 
				$this->route = substr($_SERVER['PATH_INFO'], 1);
			elseif ($this->urlModel == URL_REWRITE && isset($_GET['url'])) 
				$this->route = $_GET['url'];
		} else 
			$this->route = $route;
			
		///
		$this->_initUrlRoutes();
	}
	
	/**
	 * 分析路由信息
	 * // 每条路由信息如下：
	 * 	array(
	 * 		'pattern' => '/^list-(\d+).html$/i',
	 * 		'route' => 'site/list',
	 * 		'keys' => array('cid')
	 * 	)
	 * 
	 */
	private function _initUrlRoutes()
	{
		if (is_array($this->urlRoutes) && $this->urlRoutes) {
			$keys = array('pattern', 'route', 'keys');
			foreach ($this->urlRoutes as $i => $tmp) {
				if ( ! is_array($tmp)) 
					unset($this->urlRoutes[$i]);
			}
		} else 
			$this->urlRoutes = array();
	}
	
	/**
	 * 分析请求信息
	 * // 解析配置的路由
	 * // 解析出确认子应用
	 * // 解析出控制器
	 */
	private function _initQuery()
	{
		foreach ($this->urlRoutes as $r) {
			if (preg_match($r['pattern'], $this->route, $matches)) {
				array_shift($matches);
				$this->route = $r['route'];
				foreach ($r['keys'] as $i => $key) 
					$_GET[$key] = $matches[$i];
					
				break;
			}
		}
		
		///
		if ($this->route) {
			if ($parts = explode('/', $this->route)) {
				$subApps = App::O('main.appSubs');
				if (is_array($subApps) && array_key_exists($parts[0], $subApps)) 
					App::$__subApp = array_shift($parts);
			}
		} else 
			$parts = array();
			
		///
		if (is_array($parts) && $parts) {
			$this->ctrlData = array(
				isset($parts[0]) ? trim($parts[0]) : '',
				isset($parts[1]) ? trim($parts[1]) : ''
			);
			
			$count = count($parts);
			for ($i=2; $i<$count; $i+=2) 
				$_GET[$parts[$i]] = $parts[$i + 1];
		}
	}
	
	
	/// 以下方法提供为静态调用 ///
	
	
	/**
	 * 返回客户端IP地址
	 * 
	 * @return string
	 * @static 
	 */
	static function ip()
	{
		static $ip;
		
		///
		if ( ! isset($ip)) {
			if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) 
				$ip = getenv('HTTP_CLIENT_IP');
			elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) 
				$ip = getenv('HTTP_X_FORWARDED_FOR');
			elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) 
				$ip = getenv('REMOTE_ADDR');
			elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) 
				$ip = $_SERVER['REMOTE_ADDR'];
				
			///
			preg_match("/[\d\.]{7,15}/", $ip, $m);
			$ip = $m[0] ? $m[0] : 'unknown';
		}
		
		///
		return $ip;
	}
	
	/**
	 * 判断HTTP请求
	 * // 是否POST方法
	 * 
	 * @return bool
	 * @static 
	 */
	static function isPost()
	{
		static $flag;
		
		///
		if ( ! isset($flag)) 
			$flag = strtoupper($_SERVER['REQUEST_METHOD']) == 'POST';
			
		///
		return $flag;
	}
	
	/**
	 * 判断HTTP请求
	 * // 是否通过XMLHttp发起的
	 * 
	 * @return bool
	 * @static 
	 */
	static function isAjax()
	{
		static $flag;
		
		///
		if ( ! isset($flag)) {
			$tmp = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? strtoupper($_SERVER['HTTP_X_REQUESTED_WITH']) : '';
			$flag = $tmp == 'XMLHTTPREQUEST';
		}
		
		///
		return $flag;
	}
	
	/**
	 * 判断HTTP请求
	 * // 是否搜索引擎爬虫
	 * 
	 * @return bool
	 * @static 
	 */
	static function isRobot()
	{
		static $flag;
		
		/// 
		if ( ! isset($flag)) {
			$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
			$kwSpiders = array('bot', 'crawl', 'spider' ,'slurp', 'sohu-search', 'lycos', 'robozilla');
			$kwBrowsers = array('msie', 'netscape', 'opera', 'konqueror', 'mozilla');
			
			///
			if (strpos($useragent, 'http://') === false && self::_astrpos($useragent, $kwBrowsers)) 
				$flag = false;
			else if (self::_astrpos($useragent, $kwSpiders)) 
				$flag =  true;
			else 
				$flag = false;
		}
		
		///
		return $flag;
	}
	
	/**
	 * 判断HTTP请求
	 * // 是否通过手机访问
	 * 
	 * @return bool
	 * @static 
	 */
	static function isMobile()
	{
		static $flag;
		
		///
		if ( ! isset($flag)) {
			$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
			$kwBrowsers = array('iphone', 'android', 'phone', 'mobile', 'wap', 'netfront', 'java', 'opera mobi', 'opera mini',
				'ucweb', 'windows ce', 'symbian', 'series', 'webos', 'sony', 'blackberry', 'dopod', 'nokia', 'samsung',
				'palmsource', 'xda', 'pieplus', 'meizu', 'midp', 'cldc', 'motorola', 'foma', 'docomo', 'up.browser',
				'up.link', 'blazer', 'helio', 'hosin', 'huawei', 'novarra', 'coolpad', 'webos', 'techfaith', 'palmsource',
				'alcatel', 'amoi', 'ktouch', 'nexian', 'ericsson', 'philips', 'sagem', 'wellcom', 'bunjalloo', 'maui', 'smartphone',
				'iemobile', 'spice', 'bird', 'zte-', 'longcos', 'pantech', 'gionee', 'portalmmm', 'jig browser', 'hiptop',
				'benq', 'haier', '^lct', '320x320', '240x320', '176x220');
				
			///
			$flag = self::_astrpos($useragent, $kwBrowsers);
		}
		
		///
		return $flag;
	}
	
	/**
	 * 检测在指定数组中元素是否有包含在查询的字符串中
	 * 
	 * @param string $string 待查询的字符串
	 * @param array $array 查询的数组
	 * @return bool
	 * @static 
	 */
	static function _astrpos($string, $array)
	{
		if (empty($string)) 
			return false;
			
		///
		foreach((array)$array as $v) {
			if (strpos($string, $v) !== false) 
				return true;
		}
		
		return false;
	}
}
